package service

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	"gitee.com/zhyclouds/fable-scribe/internal/domain"
	"gitee.com/zhyclouds/fable-scribe/internal/repository"
	"gitee.com/zhyclouds/fable-scribe/internal/service/image"
	"gitee.com/zhyclouds/fable-scribe/internal/service/text"
)

var (
	ErrMongoRecodeNotFound = repository.ErrMongoRecodeNotFound
)

// ComicService 漫画生成服务接口
type ComicService interface {
	// GenerateComic 生成漫画图片
	GenerateComic(ctx context.Context, req domain.ComicGenerateRequest) (domain.ComicGenerateResponse, error)
	// GenerateComicSeries 生成漫画组图并存储
	GenerateComicSeries(ctx context.Context, uid int64, req domain.ComicGenerateRequest) ([]domain.Draw, error)
	GenerateList(ctx context.Context, uid int64, offset int, limit int) ([]domain.Comic, error)
	DeleteComicById(ctx context.Context, comicId int64, uid int64) error
}

// MultiTurnComicService 多轮漫画生成服务
type MultiTurnComicService struct {
	textService  text.Service
	imageService image.Service
	comicRepo    repository.ComicRepository
}

// NewMultiTurnComicService 创建漫画生成服务实例
func NewMultiTurnComicService(textService text.Service, imageService image.Service, comicRepo repository.ComicRepository) ComicService {
	return &MultiTurnComicService{
		textService:  textService,
		imageService: imageService,
		comicRepo:    comicRepo,
	}
}

func (s *MultiTurnComicService) DeleteComicById(ctx context.Context, comicId int64, uid int64) error {
	return s.comicRepo.DeleteComicById(ctx, comicId, uid)
}

func (s *MultiTurnComicService) GenerateList(ctx context.Context, uid int64, offset int, limit int) ([]domain.Comic, error) {
	return s.comicRepo.GetByUid(ctx, uid, offset, limit)
}

// GenerateComic 生成漫画图片（单张）
func (s *MultiTurnComicService) GenerateComic(ctx context.Context, req domain.ComicGenerateRequest) (domain.ComicGenerateResponse, error) {
	// 生成文生图模型的prompt
	prompt, err := s.generateImagePrompt(ctx, req)
	if err != nil {
		return domain.ComicGenerateResponse{}, fmt.Errorf("生成图片提示词失败: %w", err)
	}

	// 调用文生图模型生成图片
	imageReq := domain.ImageGenerationRequest{
		Prompt: prompt,
		Size:   "1024x1024", // 使用合适的图片尺寸
	}

	imageResps, err := s.imageService.GenerateImage(ctx, imageReq)
	if err != nil {
		return domain.ComicGenerateResponse{}, fmt.Errorf("生成图片失败: %w", err)
	}

	if len(imageResps) == 0 || imageResps[0].URL == "" {
		return domain.ComicGenerateResponse{}, fmt.Errorf("文生图模型返回空图片")
	}

	// 返回响应
	return domain.ComicGenerateResponse{
		Image:       imageResps[0].URL,
		CreatedTime: time.Now().Unix(),
	}, nil
}

// storyboardResult 分镜结果结构体
type storyboardResult struct {
	Scenes       []string `json:"scenes"`
	ScenesDetail []string `json:"scenes_detail"`
}

// GenerateComicSeries 生成漫画组图并存储
func (s *MultiTurnComicService) GenerateComicSeries(ctx context.Context, uid int64, req domain.ComicGenerateRequest) ([]domain.Draw, error) {
	// 1. 生成包含分镜文案和画面描述的JSON内容
	storyboardPrompt := s.generateStoryboardPrompt(req)
	txtReq := domain.TextGenerationRequest{
		Prompt:  storyboardPrompt,
		ModelID: "doubao-seed-1-6-251015",
	}

	txtResp, err := s.textService.GenerateText(ctx, txtReq)
	if err != nil {
		return nil, fmt.Errorf("生成分镜内容失败: %w", err)
	}

	// 解析生成的JSON分镜内容
	var storyboard storyboardResult
	if err := json.Unmarshal([]byte(txtResp.Content), &storyboard); err != nil {
		// 如果解析失败，记录错误但继续使用原始内容作为prompt
		// 这样即使JSON格式有问题，至少可以尝试生成图片
		fmt.Printf("解析分镜JSON失败: %v\n", err)
	}

	// 2. 将分镜内容作为prompt，调用文生图模型生成组图
	imageReq := domain.ImageGenerationRequest{
		Prompt:    txtResp.Content, // 使用包含scenes和scenes_detail的JSON作为prompt
		Size:      "1024x1024",     // 使用合适的图片尺寸
		MaxImages: 10,              // 设置最大生成10张图片（与分镜数量上限一致）
	}

	imageResps, err := s.imageService.GenerateImage(ctx, imageReq)
	if err != nil {
		return nil, fmt.Errorf("生成组图失败: %w", err)
	}

	if len(imageResps) == 0 {
		return nil, fmt.Errorf("文生图模型未返回任何图片")
	}

	// 3. 构建Draw数组，尽可能使用对应的分镜文案作为描述
	draws := make([]domain.Draw, 0, len(imageResps))
	for i, resp := range imageResps {
		if resp.URL != "" {
			desc := req.Text // 默认使用小说内容
			// 如果成功解析了JSON且有对应的分镜文案，则使用分镜文案
			if len(storyboard.Scenes) > i {
				desc = storyboard.Scenes[i]
			}
			draws = append(draws, domain.Draw{
				Desc: desc,
				Url:  resp.URL,
			})
		}
	}

	if len(draws) == 0 {
		return nil, fmt.Errorf("未能生成任何漫画图片")
	}

	// 4. 创建漫画实体并存储
	comic := domain.Comic{
		Uid:        uid,
		Text:       req.Text,
		Style:      req.Style,
		Tone:       req.Tone,
		Gender:     req.Gender,
		Appearance: req.Appearance,
		Draws:      draws,
		Ctime:      time.Now().Unix(),
		Utime:      time.Now().Unix(),
	}

	if err := s.comicRepo.Insert(ctx, comic); err != nil {
		return nil, fmt.Errorf("存储漫画失败: %w", err)
	}

	return draws, nil
}

// generateStoryboardPrompt 生成分镜处理的提示词
func (s *MultiTurnComicService) generateStoryboardPrompt(req domain.ComicGenerateRequest) string {
	prompt := `# 角色 

 你是一位**漫画创作大师**。 

 ## 任务 

 贴合用户指定的**小说内容、漫画风格和基调**，创作**贴合小说情节、线性连贯的、分镜-文案-画面严格顺序对应的漫画内容**： 
 - 核心约束：**分镜拆分→文案（scenes）→画面描述（scenes_detail）必须1:1顺序绑定**，从故事开头到结尾，像「放电影」一样按时间线推进，绝无错位。 

 ## 工作流程 

 1. 充分理解用户诉求。 优先按照用户的创作细节要求执行（如果有） 
 2. **分镜结构与数量:** 
     * 将内容浓缩成 **5~10** 个关键分镜，最多10个（不能超过10个）。 
     * 必须遵循用户给出的小说内容进行清晰的叙事。 
 3. **文案与画面 (一一对应):** 
     * **文案 ("scenes"字段):** 为每个分镜创作贴合画面场景的文案。文案必须与画面描述紧密贴合，共同服务。**禁止在文案中使用任何英文引号 ("")**。不能超过10个。 
     * **画面 ("scenes_detail"字段):** 为每个分镜构思详细的画面。画风必须贴合用户诉求和小说片段氛围。描述需包含构图、光影、色彩、角色神态等关键视觉要素，达到可直接用于图片生成的标准。 
 4. 整合输出：将所有内容按指定 JSON 格式整理输出。 

 ## 安全限制 
 生成的内容必须严格遵守以下规定： 
 1.  **禁止暴力与血腥:** 不得包含任何详细的暴力、伤害、血腥或令人不适的画面描述。 
 2.  **禁止色情内容:** 不得包含任何色情、性暗示或不适宜的裸露内容。 
 3.  **禁止仇恨与歧视:** 不得包含针对任何群体（基于种族、宗教、性别、性取向等）的仇恨、歧视或攻击性言论。 
 4.  **禁止违法与危险行为:** 不得描绘或鼓励任何非法活动、自残或危险行为。 
 5.  **确保普遍适宜性:** 整体内容应保持在社会普遍接受的艺术创作范围内，避免极端争议性话题。 

 ## 用户输入
 小说片段：%s
 漫画风格：%s
 画面基调：%s`

	result := fmt.Sprintf(prompt, req.Text, req.Style, req.Tone)

	// 如果用户提供了角色性别信息
	if req.Gender != "" {
		result += fmt.Sprintf("\n 角色性别：%s", req.Gender)
	}

	// 如果用户提供了角色样貌信息
	if req.Appearance != "" {
		result += fmt.Sprintf("\n 角色样貌：%s", req.Appearance)
	}

	result += `

 ## 输出格式要求 
 整理成以下JSON格式，scenes 和 scenes_detail 要与分镜保持顺序一致，一一对应，最多10个（不能超过10个）： 
 { 
 "scenes": [ 
 "分镜1的文案，符合设定。", 
 "分镜2的文案" 
 ], 
 "scenes_detail": [ 
 "图片1：这是第一张漫画的画面描述。必须以'图片'+序号开头。要有强烈的视觉感，详细描述构图（如特写、远景）、光影、色彩、角色表情、动作和环境细节，符合生图提示词的要求。", 
 "图片2：" 
 ] 
 }`

	return result
}

// generateGroupImagePrompt 生成漫画组图提示词
func (s *MultiTurnComicService) generateGroupImagePrompt(ctx context.Context, req domain.ComicGenerateRequest) (string, error) {
	// 构建组图提示词模板
	groupPrompt := `
请根据以下小说片段生成一个详细的文生图提示词，用于生成漫画风格的组图（3-5张连续画面）：

小说片段：%s

漫画风格：%s
画面基调：%s
`

	prompt := fmt.Sprintf(groupPrompt, req.Text, req.Style, req.Tone)

	// 如果用户提供了角色性别信息
	if req.Gender != "" {
		prompt += fmt.Sprintf("角色性别：%s\n", req.Gender)
	}

	// 如果用户提供了角色样貌信息
	if req.Appearance != "" {
		prompt += fmt.Sprintf("角色样貌：%s\n", req.Appearance)
	}

	prompt += `
请你作为一个专业的漫画提示词工程师，将上述小说片段转化为一个详细、具体、适合AI绘画的提示词。
提示词应该包含：
1. 故事的关键场景和转折点，能够形成3-5张连续的画面
2. 角色细节和动作描述
3. 艺术风格特征
4. 光照和色彩要求
5. 构图建议

请生成一个能够让AI理解并生成连贯故事分镜的提示词，保持故事的连贯性和视觉的一致性。
请只返回提示词内容，不要添加任何其他说明文字。
`

	// 调用文本生成服务生成提示词
	txtReq := domain.TextGenerationRequest{
		Prompt:  prompt,
		ModelID: "doubao-seed-1-6-251015",
	}

	txtResp, err := s.textService.GenerateText(ctx, txtReq)
	if err != nil {
		return "", err
	}

	return txtResp.Content, nil
}

// generateShotImagePrompt 为单个分镜生成图片提示词
func (s *MultiTurnComicService) generateShotImagePrompt(ctx context.Context, req domain.ComicGenerateRequest, shot string) (string, error) {
	// 构建分镜图片提示词模板
	shotPromptTemplate := `
请根据以下分镜描述生成一个详细的文生图提示词，用于生成漫画风格的图片：

分镜描述：%s

漫画风格：%s
画面基调：%s
`

	prompt := fmt.Sprintf(shotPromptTemplate, shot, req.Style, req.Tone)

	// 如果用户提供了角色性别信息
	if req.Gender != "" {
		prompt += fmt.Sprintf("角色性别：%s\n", req.Gender)
	}

	// 如果用户提供了角色样貌信息
	if req.Appearance != "" {
		prompt += fmt.Sprintf("角色样貌：%s\n", req.Appearance)
	}

	prompt += `
请你作为一个专业的漫画提示词工程师，将上述分镜描述转化为一个详细、具体、适合AI绘画的提示词。
提示词应该包含：
1. 场景描述
2. 角色细节（如果有）
3. 艺术风格特征
4. 光照和色彩要求
5. 构图建议

请只返回提示词内容，不要添加任何其他说明文字。
`

	// 调用文本生成服务生成提示词
	txtReq := domain.TextGenerationRequest{
		Prompt:  prompt,
		ModelID: "doubao-seed-1-6-251015",
	}

	txtResp, err := s.textService.GenerateText(ctx, txtReq)
	if err != nil {
		return "", err
	}

	return txtResp.Content, nil
}

// generateImagePrompt 生成文生图模型的提示词
func (s *MultiTurnComicService) generateImagePrompt(ctx context.Context, req domain.ComicGenerateRequest) (string, error) {
	// 构建提示词模板
	promptTemplate := `
请根据以下小说片段生成一个详细的文生图提示词，用于生成漫画风格的图片：

小说片段：%s

漫画风格：%s
画面基调：%s
`

	prompt := fmt.Sprintf(promptTemplate, req.Text, req.Style, req.Tone)

	// 如果用户提供了角色性别信息
	if req.Gender != "" {
		prompt += fmt.Sprintf("角色性别：%s\n", req.Gender)
	}

	// 如果用户提供了角色样貌信息
	if req.Appearance != "" {
		prompt += fmt.Sprintf("角色样貌：%s\n", req.Appearance)
	}

	prompt += `
请你作为一个专业的漫画提示词工程师，将上述信息转化为一个详细、具体、适合AI绘画的提示词。
提示词应该包含：
1. 场景描述
2. 角色细节（如果有）
3. 艺术风格特征
4. 光照和色彩要求
5. 构图建议

请只返回提示词内容，不要添加任何其他说明文字。
`

	// 调用文本生成服务生成提示词
	txtReq := domain.TextGenerationRequest{
		Prompt:  prompt,
		ModelID: "doubao-seed-1-6-251015",
	}

	txtResp, err := s.textService.GenerateText(ctx, txtReq)
	if err != nil {
		return "", err
	}

	return txtResp.Content, nil
}
